import type { MiddlewareHandler } from "hono";
import { isBlank, reverseStr } from "ph-utils";
import { hashDigest } from "ph-utils/crypto_node";
import { body } from "../libs/response/index.js";

const APP_SECRET = "402C5A6FE4C04C7D269C4532BAECC8EE";

const ITEM_RE = /(\w+)="([^"]+)"/g;

type ValidSignatureOption = {
  ignoreUrls?: string[];
};

function parseSignature(xsignature: string) {
  let xsignatureData: any = {};
  let match: RegExpExecArray | null;
  while ((match = ITEM_RE.exec(xsignature)) != null) {
    xsignatureData[match[1]] = match[2];
  }
  return xsignatureData as {
    nonce_str: string;
    timestamp: string;
    signature: string;
    appid?: string;
  };
}

function generateSignature(
  appid: string,
  method: string,
  url: string,
  timestamp: string,
  nonce_str: string,
  body?: string
) {
  const sign_nonce = reverseStr(nonce_str);
  let signRaw = `${appid},${method},${url},${timestamp},${sign_nonce},`;
  if (!isBlank(body)) {
    signRaw += `${body},`;
  }
  return btoa(reverseStr(hashDigest(signRaw)));
}

export default function validSignature(
  option?: ValidSignatureOption
): MiddlewareHandler {
  const ignoreUrls = (option && option.ignoreUrls) || [];
  return async (c, next) => {
    const url = new URL(c.req.url);
    if (ignoreUrls.includes(url.pathname)) {
      await next();
      return;
    }
    let isVery = false; // 是否验证通过
    let xsignature = c.req.header("X-Signature");
    // 获取签名信息
    if (!isBlank(xsignature)) {
      const signData = parseSignature(xsignature as string);
      if (
        !isBlank(signData.nonce_str) &&
        !isBlank(signData.timestamp) &&
        !isBlank(signData.signature)
      ) {
        const timestamp = Math.floor(Date.now() / 1000);
        // 只接受最近15分钟的请求
        if (timestamp - Number(signData.timestamp) <= 900) {
          const appid = signData.appid;
          const method = c.req.method;
          const urlStr = `${url.pathname}${url.search}`;
          let reqBody;
          if (method === "POST") {
            reqBody = await c.req.text();
          }
          let app_secret: string;
          if (appid == null) {
            app_secret = APP_SECRET;
          } else {
            // 开放给第三方平台时, 通过 appid 获取 app_secret
            app_secret = APP_SECRET;
          }
          // 生成签名
          const signature = generateSignature(
            app_secret,
            method,
            urlStr,
            signData.timestamp,
            signData.nonce_str,
            reqBody
          );
          if (signature === signData.signature) {
            isVery = true;
          }
        }
      }
    }
    if (isVery) {
      await next();
      return;
    }
    return c.json(body(null, 40001));
  };
}
